﻿using System;
using System.Linq;
using System.Windows.Documents;
using ForumsBrowser.BusinessObjects;
using System.Windows.Media;
using HTMLConverter;
using System.Text.RegularExpressions;
using System.Windows;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Media.Animation;

namespace ForumsBrowser
{
    public class FlowDocumentGenerator
    {
        public static FlowDocument Generate(Thread thread)
        {
            FlowDocument doc = new FlowDocument();
            doc.Foreground = Brushes.Black;
            doc.Background = new RadialGradientBrush(Colors.Gray, Colors.Black);
            doc.Blocks.Add(new BlockUIContainer(new ThreadHeader { Thread = thread }));

            foreach (Message msg in thread.Messages)
            {
                Block block = GetMessageSection(msg);
                EnableHyperlinks(block);
                doc.Blocks.Add(block);
            }
            
            return doc;
        }

        public static FlowDocument Generate(Message msg)
        {
            FlowDocument doc = new FlowDocument();
            doc.Foreground = Brushes.Black;
            doc.Background = new RadialGradientBrush(Colors.Gray, Colors.Black);

            Section section = GetMessageSection(msg);
            EnableHyperlinks(section);
            doc.Blocks.Add(section);

            return doc;
        }

        private static Section GetMessageSection(Message msg)
        {
            Section result = new Section();

            result.Blocks.Add(GetHeaderFlowDocumentElement(msg));
            result.Blocks.Add(GetMessageTextFlowDocumentElement(msg));

            result.Background = new LinearGradientBrush(Colors.Gray, Colors.White, new Point(0, 0), new Point(0, .25));

            return result;
        }

        private static BlockUIContainer GetHeaderFlowDocumentElement(Message msg)
        {
            MessageDetailControl detail = new MessageDetailControl();
            detail.Message = msg;

            BlockUIContainer container = new BlockUIContainer(detail);
            return container;
        }


        private static Section GetMessageTextFlowDocumentElement(Message msg)
        {
            string body = PreFormatBody(msg.Body);

            var xaml = HtmlToXamlConverter.ConvertHtmlToXaml(body, false);

            Section section = ((Section)System.Windows.Markup.XamlReader.Parse(xaml));

            section.Padding = new Thickness(10,0,10,10);
            section.Margin = new Thickness(0, 0, 0, 10);
            return section;
        }

        private static string PreFormatBody(string body)
        {
            string style = "body { font-family:Verdana; font-size:12 } blockquote { background-color:gray }";
            body = "<html><head><style type=\"text/css\">" + style + "</style></head><body>" + body + "</body></html>";

            // create hard breaks to adjust for the xaml converter. 
            foreach (Match match in Regex.Matches(body, "<pre>.+?(</pre>|$)", RegexOptions.Singleline))
                body = body.Replace(match.Value, match.Value.Replace("\n", "<br/>"));

            // format the code.  This part needs work. 
            foreach (Match match in Regex.Matches(body, "<pre lang=(.+?)>(.+?)</pre>", RegexOptions.Singleline))
                body = body.Replace(match.Value, "<pre>" + CodeFormatting.CodeFormatterFactory.GetFormatter(match.Groups[1].Value).Format(match.Groups[2].Value) + "</pre>");

            return body;
        }

        // Recursively searches out and enables hyperlinks in the document. 
        private static void EnableHyperlinks(TextElement doc)
        {
            if (doc is List)
            {
                foreach (var item in ((List)doc).ListItems)
                    EnableHyperlinks(item);
            }
            else if (doc is Paragraph)
            {
                foreach (var item in ((Paragraph)doc).Inlines)
                    EnableHyperlinks(item);
            }
            else if (doc is Section)
            {
                foreach (var item in ((Section)doc).Blocks)
                    EnableHyperlinks(item);
            }
            else if (doc is Table)
            {
                foreach (var item in ((Table)doc).RowGroups)
                    EnableHyperlinks(item);
            }
            else if (doc is AnchoredBlock)
            {
                foreach (var item in ((AnchoredBlock)doc).Blocks)
                    EnableHyperlinks(item);
            }
            else if (doc is Hyperlink)
            {
                ((Hyperlink)doc).Click += new RoutedEventHandler((o, e) => Process.Start(((Hyperlink)doc).NavigateUri.AbsoluteUri));
                foreach (var item in ((Hyperlink)doc).Inlines)
                    EnableHyperlinks(item);
            }
            else if (doc is Span)
            {
                foreach (var item in ((Span)doc).Inlines)
                    EnableHyperlinks(item);
            }
            else if (doc is TableCell)
            {
                foreach (var item in ((TableCell)doc).Blocks)
                    EnableHyperlinks(item);
            }
            else if (doc is TableRow)
            {
                foreach (var item in ((TableRow)doc).Cells)
                    EnableHyperlinks(item);
            }
            else if (doc is TableRowGroup)
            {
                foreach (var item in ((TableRowGroup)doc).Rows)
                    EnableHyperlinks(item);
            }
        }
    }
}
